home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / PowerPlant / LPasswordField / LPasswordField.cp < prev    next >
Text File  |  1995-11-03  |  31KB  |  1,351 lines

  1. /*    NAME:
  2.         LPasswordField.cp
  3.  
  4.     WRITTEN BY:
  5.         Dair Grant, dair@kagi.com
  6.                 
  7.     DESCRIPTION:
  8.         A Pane containing editable text, which only displays bullet characters.
  9.         
  10.         Use an LPasswordField for small amounts of monstyled text, such as a
  11.         text entry field in a dialog box. LPasswordField derives from the
  12.         LEditField class, so similar restrictions apply to its usage (it uses
  13.         TextEdit, and it's not a View, so you can't put a PasswordField in a
  14.         Scroller).
  15.         
  16.         LPasswordField should behave *exactly* like EditFields, the only
  17.         difference being that characters are always displayed as bullets.
  18.         You use the same routines (SetDescriptor/GetDescriptor and SetValue/
  19.         GetValue) to manipulate the text, and the same commands can be
  20.         performed on it (cut, copy, paste, etc). The LPasswordField takes
  21.         care of ensuring that only bullets are ever displayed.
  22.         
  23.         The bullet character defaults to '•'. The SetBullet method allows
  24.         this to be changed.
  25.         
  26.         To use a LPasswordField, create and position an EditField with
  27.         Constructor, and set the class ID to 'pass' once you're happy with
  28.         it. Then include LPasswordField.h in the relevent source files,
  29.         add LPasswordField.cp to your project, and put the line
  30.         
  31.             URegistrar::RegisterClass(LPasswordField::class_ID,
  32.                                         LPasswordField::CreatePasswordFieldStream);
  33.  
  34.         in your applications constructor.
  35.         
  36.         You may use the LPasswordField class in any project you write,
  37.         without restriction. Comments, bugs, or suggestions are more than
  38.         welcome - send them to dair@kagi.com.
  39.         
  40.     ___________________________________________________________________________
  41.  
  42.     VERSION HISTORY:
  43.         1.0: (June 1995, dg)
  44.             •    First public release.
  45.  
  46.     ___________________________________________________________________________
  47. */
  48. //=============================================================================
  49. //        Include files
  50. //-----------------------------------------------------------------------------
  51. #ifdef PowerPlant_PCH
  52. #include PowerPlant_PCH
  53. #endif
  54.  
  55. #include <Scrap.h>
  56. #include <Script.h>
  57. #include <TextEdit.h>
  58. #include <ToolUtils.h>
  59.  
  60. #include <LCommander.h>
  61. #include <LEditField.h>
  62. #include <LPane.h>
  63. #include <LPasswordField.h>
  64. #include <LStream.h>
  65. #include <PP_KeyCodes.h>
  66. #include <PP_Messages.h>
  67. #include <UDrawingState.h>
  68. #include <UKeyFilters.h>
  69. #include <UTETextAction.h>
  70. #include <UTextTraits.h>
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86. //=============================================================================
  87. //        Private defines
  88. //-----------------------------------------------------------------------------
  89. #define kHiddenTEOffset                1000            // Offset for hidden TE record
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105. //=============================================================================
  106. //        LPasswordField::CreatePasswordFieldStream
  107. //-----------------------------------------------------------------------------
  108. //        Create a new PasswordField object from the data in a Stream.
  109. //-----------------------------------------------------------------------------
  110. LPasswordField *LPasswordField::CreatePasswordFieldStream(LStream *inStream)
  111. {
  112.     return (new LPasswordField(inStream));
  113. }
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129. //=============================================================================
  130. //        LPasswordField::LPasswordField
  131. //-----------------------------------------------------------------------------
  132. //        Default constructor.
  133. //-----------------------------------------------------------------------------
  134. LPasswordField::LPasswordField() : LEditField()
  135. {
  136.     InitPassField(editAttr_Box);
  137. }
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153. //=============================================================================
  154. //        LPasswordField::LPasswordField
  155. //-----------------------------------------------------------------------------
  156. //        Copy constructor.
  157. //-----------------------------------------------------------------------------
  158. LPasswordField::LPasswordField(const LPasswordField    &inOriginal) : LEditField(inOriginal)
  159. {    Rect        viewRect = {0, 0, 0, 0};
  160.     Str255        theStr;
  161.  
  162.  
  163.  
  164.     // The LEditField constructor will have build our mTextEditH member.
  165.     // We move it somewhere off screen so it won't be visible.
  166.     ::OffsetRect(&(*mTextEditH)->viewRect, kHiddenTEOffset, kHiddenTEOffset);
  167.  
  168.  
  169.     // Create the 'bullet' TextEdit record    
  170.     mBulletTextEditH = ::TENew(&viewRect, &viewRect);
  171.  
  172.  
  173.     // Set our descriptor correctly    and align everything correctly
  174.     SetDescriptor(inOriginal.GetDescriptor(theStr));
  175.     AlignTextEditRects();
  176. }
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192. //=============================================================================
  193. //        LPasswordField::LPasswordField
  194. //-----------------------------------------------------------------------------
  195. //        Construct from input parameters.
  196. //-----------------------------------------------------------------------------
  197. LPasswordField::LPasswordField(const    SPaneInfo    &inPaneInfo,
  198.                                         Str255            inString,
  199.                                         ResIDT            inTextTraitsID,
  200.                                         Int16            inMaxChars,
  201.                                         Boolean            inHasBox,
  202.                                         Boolean            inHasWordWrap,
  203.                                         KeyFilterFunc    inKeyFilter,
  204.                                         LCommander        *inSuper) :
  205.                 LEditField(inPaneInfo, inString, inTextTraitsID, inMaxChars,
  206.                             inHasBox, inHasWordWrap, inKeyFilter, inSuper)
  207. {    Uint8        attributes = 0;
  208.  
  209.  
  210.  
  211.     // Set our attributes, then initialise ourself with them
  212.     if (inHasBox)
  213.         attributes += editAttr_Box;
  214.     if (inHasWordWrap)
  215.         attributes += editAttr_WordWrap;
  216.     InitPassField(attributes);
  217.  
  218.  
  219.     // If we've been given a string, put it into the visible
  220.     // TextEdit record and convert it to bullets
  221.     if (inString[0] > 0)
  222.         {
  223.         ::TESetText(inString + 1, inString[0], mBulletTextEditH);
  224.         SetTextToBullets(mBulletTextEditH);
  225.         }
  226.  
  227.  
  228.     // Align the TextEdit records and select the text, if any
  229.     AlignTextEditRects();
  230.     SelectAll();
  231. }
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247. //=============================================================================
  248. //        LPasswordField::LPasswordField
  249. //-----------------------------------------------------------------------------
  250. //        Construct from input parameters.
  251. //-----------------------------------------------------------------------------
  252. LPasswordField::LPasswordField(const    SPaneInfo    &inPaneInfo,
  253.                                         Str255            inString,
  254.                                         ResIDT            inTextTraitsID,
  255.                                         Int16            inMaxChars,
  256.                                         Uint8            inAttributes,
  257.                                         KeyFilterFunc    inKeyFilter,
  258.                                         LCommander        *inSuper) :
  259.                 LEditField(inPaneInfo, inString, inTextTraitsID, inMaxChars,
  260.                             inAttributes, inKeyFilter, inSuper)
  261. {
  262.  
  263.     // Initialise ourselves with the supplied attributes
  264.     InitPassField(inAttributes);
  265.  
  266.  
  267.     // If we've been given a string, put it into the visible
  268.     // TextEdit record and convert it to bullets
  269.     if (inString[0] > 0)
  270.         {
  271.         ::TESetText(inString + 1, inString[0], mBulletTextEditH);
  272.         SetTextToBullets(mBulletTextEditH);
  273.         }
  274.  
  275.  
  276.     // Align the TextEdit records and select the text, if any
  277.     AlignTextEditRects();
  278.     SelectAll();
  279. }
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295. //=============================================================================
  296. //        LPasswordField::LPasswordField
  297. //-----------------------------------------------------------------------------
  298. //        Construct from the data in a stream.
  299. //-----------------------------------------------------------------------------
  300. LPasswordField::LPasswordField(LStream *inStream) : LEditField(inStream)
  301. {    Uint8        attributes = 0;
  302.  
  303.  
  304.  
  305.     // The LEditField constructor has built itself from the data in
  306.     // inStream, but didn't save the attributes away anywhere. We
  307.     // have to recreate the attributes ourselves by hand.
  308.     if (mHasBox)
  309.         attributes |= editAttr_Box;
  310.  
  311.     if (mHasWordWrap)
  312.         attributes |= editAttr_WordWrap;
  313.     
  314.     if (TEFeatureFlag(teFAutoScr, teBitTest, mTextEditH) == teBitSet)
  315.         attributes |= editAttr_AutoScroll;
  316.  
  317.     if (TEFeatureFlag(teFTextBuffering, teBitTest, mTextEditH) == teBitSet)
  318.         attributes |= editAttr_TextBuffer;
  319.  
  320.     if (TEFeatureFlag(teFOutlineHilite, teBitTest, mTextEditH) == teBitSet)
  321.         attributes |= editAttr_OutlineHilite;
  322.  
  323.     if (TEFeatureFlag(teFInlineInput, teBitTest, mTextEditH) == teBitSet)
  324.         attributes |= editAttr_InlineInput;
  325.  
  326.     if (TEFeatureFlag(teFUseTextServices, teBitTest, mTextEditH) == teBitSet)
  327.         attributes |= editAttr_TextServices;
  328.  
  329.  
  330.  
  331.     // Initialise ourselves from these attributes
  332.     InitPassField(attributes);
  333.  
  334.  
  335.     // Set the visible TextEdit record to match the hidden one
  336.     SetVisibleFromHidden();
  337.  
  338.  
  339.     // Align the TextEdit records and select the text, if any
  340.     AlignTextEditRects();
  341.     SelectAll();
  342. }
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358. //=============================================================================
  359. //        LPasswordField::InitPassField
  360. //-----------------------------------------------------------------------------
  361. //        Initialise the member variables of a PassField.
  362. //
  363. //        We also fudge some of the things our parent (LEditField) set up
  364. //        earlier.
  365. //-----------------------------------------------------------------------------
  366. void LPasswordField::InitPassField(Uint8 inAttributes)
  367. {    Rect        viewRect = {0, 0, 0, 0};
  368.  
  369.  
  370.  
  371.     // The LEditField constructor will have build our mTextEditH member.
  372.     // We move it somewhere off screen so it won't be visible.
  373.     OffsetRect(&(*mTextEditH)->viewRect, kHiddenTEOffset, kHiddenTEOffset);
  374.  
  375.  
  376.     // Set the focus to be ourselves, rather than the EditField
  377.     StFocusAndClipIfHidden    focus(this);
  378.  
  379.  
  380.  
  381.     // Initialise our internal variables    
  382.     mBulletTextEditH    = ::TENew(&viewRect, &viewRect);
  383.     mBullet                = '•';
  384.  
  385.  
  386.  
  387.     // Set the optional features for the TextEdit field    
  388.     ::TEFeatureFlag(teFAutoScr,
  389.             ((inAttributes & editAttr_AutoScroll) != 0) ?
  390.                 teBitSet : teBitClear, mBulletTextEditH);
  391.  
  392.     ::TEFeatureFlag(teFTextBuffering,
  393.             ((inAttributes & editAttr_TextBuffer) != 0) ?
  394.                 teBitSet : teBitClear, mBulletTextEditH);
  395.  
  396.     ::TEFeatureFlag(teFOutlineHilite,
  397.             ((inAttributes & editAttr_OutlineHilite) != 0) ?
  398.                 teBitSet : teBitClear, mBulletTextEditH);
  399.  
  400.     ::TEFeatureFlag(teFInlineInput,
  401.             ((inAttributes & editAttr_InlineInput) != 0) ?
  402.                 teBitSet : teBitClear, mBulletTextEditH);
  403.  
  404.     ::TEFeatureFlag(teFUseTextServices,
  405.             ((inAttributes & editAttr_TextServices) != 0) ?
  406.                 teBitSet : teBitClear, mBulletTextEditH);
  407. }
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423. //=============================================================================
  424. //        LPasswordField::~LPasswordField
  425. //-----------------------------------------------------------------------------
  426. //        Destructor
  427. //-----------------------------------------------------------------------------
  428. LPasswordField::~LPasswordField()
  429. {
  430.     if (mBulletTextEditH != nil)
  431.         ::TEDispose(mBulletTextEditH);
  432. }
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447.  
  448. //=============================================================================
  449. //        LPasswordField::SetDescriptor
  450. //-----------------------------------------------------------------------------
  451. //        Set the contents of a PasswordField from a Pascal string.
  452. //
  453. //        We call our parent class to set the text of the offscreen item
  454. //        correctly, then resynch the visible field.
  455. //-----------------------------------------------------------------------------
  456. void LPasswordField::SetDescriptor(ConstStr255Param inDescriptor)
  457. {
  458.  
  459.     // Call our parent class
  460.     LEditField::SetDescriptor(inDescriptor);
  461.  
  462.  
  463.     // Resynch the visible field, and redraw    
  464.     SetVisibleFromHidden();
  465.     Refresh();
  466. }
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480.  
  481.  
  482. //=============================================================================
  483. //        LPasswordField::SetBullet
  484. //-----------------------------------------------------------------------------
  485. //        Set the bullet character to be used.
  486. //-----------------------------------------------------------------------------
  487. void LPasswordField::SetBullet(Int16 inBullet)
  488. {
  489.     mBullet = inBullet;
  490.     Refresh();
  491. }
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507. //=============================================================================
  508. //        LPasswordField::SetTextTraitsID
  509. //-----------------------------------------------------------------------------
  510. //        Set the text traits of the PasswordField.
  511. //-----------------------------------------------------------------------------
  512. void LPasswordField::SetTextTraitsID(ResIDT inTextTraitsID)
  513. {
  514.     // Call our parent class for the off screen TextEdit record
  515.     LEditField::SetTextTraitsID(inTextTraitsID);
  516.  
  517.     // Set the visible TextEdit record
  518.     UTextTraits::SetTETextTraits(mTextTraitsID, mBulletTextEditH);
  519. }
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535. //=============================================================================
  536. //        LPasswordField::DrawSelf
  537. //-----------------------------------------------------------------------------
  538. //        Draw a PasswordField.
  539. //-----------------------------------------------------------------------------
  540. void LPasswordField::DrawSelf()
  541. {    Rect        frame;
  542.  
  543.  
  544.     // Calculate the local frame rectangle
  545.     CalcLocalFrameRect(frame);
  546.  
  547.  
  548.     // Draw a border if necessary    
  549.     if (mHasBox)
  550.         {
  551.         DrawBox();
  552.         ::InsetRect(&frame, 2, 2);
  553.         }
  554.  
  555.  
  556.     // A Mac TERec stores a pointer to its owner port  We have to
  557.     // change it to the current port in case we are drawing into
  558.     // a port that is not the owner port. This happens when we are
  559.     // printing or drawing into an offscreen port.
  560.     GrafPtr    savePort = (**mBulletTextEditH).inPort;
  561.     (**mBulletTextEditH).inPort = UQDGlobals::GetCurrentPort();
  562.  
  563.     ::TEUpdate(&frame, mBulletTextEditH);
  564.     
  565.     (**mBulletTextEditH).inPort = savePort;
  566. }
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582. //=============================================================================
  583. //        LPasswordField::ClickSelf
  584. //-----------------------------------------------------------------------------
  585. //        Respond to clicks inside a PasswordField.
  586. //-----------------------------------------------------------------------------
  587. void LPasswordField::ClickSelf(const SMouseDownEvent &inMouseDown)
  588. {
  589.  
  590.     // If we're not the target, then clicking in us makes us
  591.     // the target. Since TEClick will set a new selection
  592.     // ragen, we clear the current selection range to avoid
  593.     // an ugly flash.
  594.     if (!IsTarget())
  595.         {
  596.         ::TESetSelect(0, 0, mTextEditH);
  597.         ::TESetSelect(0, 0, mBulletTextEditH);
  598.         SwitchTarget(this);
  599.         }
  600.  
  601.  
  602.     // If we're the target, handle the click with TextEdit    
  603.     if (IsTarget())
  604.         {
  605.         FocusDraw();
  606.         AdjustTextWidth(true);
  607.         ::TEClick(inMouseDown.whereLocal,
  608.                     ((inMouseDown.macEvent.modifiers & shiftKey) != 0),
  609.                     mBulletTextEditH);
  610.  
  611.  
  612.         // Since TEClick holds on to the mouse until the user lets go,
  613.         // we need to manually match up the selection of the hidden
  614.         // TextEdit record to that of the visible one.
  615.         (*mTextEditH)->selStart    = (*mBulletTextEditH)->selStart;
  616.         (*mTextEditH)->selEnd    = (*mBulletTextEditH)->selEnd;
  617.         AdjustTextWidth(false);
  618.     }
  619. }
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635. //=============================================================================
  636. //        LPasswordField::ObeyCommand
  637. //-----------------------------------------------------------------------------
  638. //        Handle standard editing commands.
  639. //-----------------------------------------------------------------------------
  640. Boolean LPasswordField::ObeyCommand(CommandT inCommand, void *ioParam)
  641. {    Boolean            cmdHandled = true;
  642.     Int32            offset;
  643.             
  644.  
  645.  
  646.     // Case out on the command    
  647.     switch (inCommand) {
  648.         case cmd_Cut:
  649.             ::TECut(mTextEditH);
  650.             PostAction(new LTECutAction(mBulletTextEditH, this, this));
  651.             break;
  652.  
  653.  
  654.         case cmd_Copy:
  655.             ::TECopy(mBulletTextEditH);
  656.             ::ZeroScrap();
  657.             ::TEToScrap();
  658.             break;
  659.  
  660.  
  661.         case cmd_Paste:
  662.             // If pasting would exceed the maximum field size, we beep
  663.             if (TooManyCharacters(::GetScrap(nil, 'TEXT', &offset)))
  664.                 ::SysBeep(30);
  665.             
  666.             
  667.             // Otherwise, past it in to both records. We need to move
  668.             // the visible TextEdit record off screen while pasting,
  669.             // since we need to munge the characters to bullets after
  670.             // they've been pasted in.
  671.             else
  672.                 {
  673.                 // Paste it into the off screen record
  674.                 PostAction(new LTEPasteAction(mTextEditH, this, this));
  675.  
  676.                 // Move the visible text record off the screen
  677.                 OffsetRect(&(*mBulletTextEditH)->viewRect, 5000, 5000);
  678.  
  679.                 // Paste in the text, and convert it to bullets
  680.                 PostAction(new LTEPasteAction(mBulletTextEditH, this, this));
  681.                 SetTextToBullets(mBulletTextEditH);
  682.             
  683.                 // Move the visible text record back onto the screen and redraw
  684.                 OffsetRect(&(*mBulletTextEditH)->viewRect, -5000, -5000);
  685.                 AlignTextEditRects();
  686.                 Refresh();
  687.                 }
  688.             break;
  689.  
  690.  
  691.         case cmd_Clear:
  692.             ::TEDelete(mTextEditH);
  693.             PostAction(new LTEClearAction(mBulletTextEditH, this, this));
  694.             break;
  695.  
  696.  
  697.         default:
  698.             // Our parent is an LEditField, not an LCommander
  699.             cmdHandled = LEditField::ObeyCommand(inCommand, ioParam);
  700.             break;
  701.         }
  702.     
  703.     
  704.     // Return as the command was handled or not
  705.     return cmdHandled;
  706. }
  707.  
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.  
  715.  
  716.  
  717.  
  718.  
  719.  
  720.  
  721.  
  722. //=============================================================================
  723. //        LPasswordField::FindCommandStatus
  724. //-----------------------------------------------------------------------------
  725. //        Pass back the status of a command.
  726. //
  727. //        We don't *really* need to override this, since all of our commands
  728. //        are tied to the current selection (which should be the same in
  729. //        both the visible and off screen TextEdit records).
  730. //
  731. //        But, we override just to make sure we can get the behaviour we want.
  732. //-----------------------------------------------------------------------------
  733. void LPasswordField::FindCommandStatus(CommandT            inCommand,
  734.                                             Boolean        &outEnabled,
  735.                                             Boolean        &outUsesMark,
  736.                                             Char16        &outMark,
  737.                                             Str255        outName)
  738. {
  739.  
  740.  
  741.     // Case out on the command
  742.     switch (inCommand) {
  743.         case cmd_Cut:
  744.         case cmd_Copy:
  745.         case cmd_Clear:
  746.             // Cut, copy, and clear are enabled if something is selected
  747.             outEnabled = ((**mBulletTextEditH).selStart != (**mBulletTextEditH).selEnd);
  748.             break;
  749.  
  750.  
  751.         case cmd_SelectAll:
  752.             // We can only select everything if there's something to select
  753.             outEnabled = (**mBulletTextEditH).teLength > 0;
  754.             break;
  755.  
  756.  
  757.         default:
  758.             // Pass it to the LEditField if it's anything else
  759.             LEditField::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
  760.             break;
  761.         }
  762. }
  763.  
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770.  
  771.  
  772.  
  773.  
  774.  
  775.  
  776.  
  777.  
  778. //=============================================================================
  779. //        LPasswordField::HandleKeyPress
  780. //-----------------------------------------------------------------------------
  781. //        Handle a key stroke directed at a PasswordField.
  782. //
  783. //        We return true if we handle the keystroke.
  784. //-----------------------------------------------------------------------------
  785. Boolean LPasswordField::HandleKeyPress(const EventRecord &inKeyEvent)
  786. {    Boolean            keyHandled        = true;
  787.     EKeyStatus        theKeyStatus    = keyStatus_Input;
  788.     Int16            theKey            = inKeyEvent.message & charCodeMask;
  789.     
  790.     
  791.  
  792.     // We always pass it up when the command key is down    
  793.     if (inKeyEvent.modifiers & cmdKey)
  794.         theKeyStatus = keyStatus_PassUp;
  795.     else if (mKeyFilter != nil)
  796.         theKeyStatus = (*mKeyFilter)(inKeyEvent);
  797.  
  798.  
  799.  
  800.     // Case out on theKeyStatus
  801.     switch (theKeyStatus) {
  802.         case keyStatus_Input:
  803.             // Check to see if we're at the character limit.
  804.             // This is NOT compatible with two-byte character systems
  805.             if (TooManyCharacters(1))
  806.                 {
  807.                 SysBeep(30);
  808.                 break;
  809.                 }
  810.  
  811.             // Otherwise, put the keystroke into the real TextEdit record
  812.             TEKey(theKey, mTextEditH);
  813.                         
  814.             // Turn the key into a bullet
  815.             theKey = mBullet;
  816.  
  817.             // Put the bullet character into the visible TextEdit record
  818.             if (mTypingAction == nil)
  819.                 {
  820.                 mTypingAction = new LTETypingAction(mBulletTextEditH, this, this);
  821.                 PostAction(mTypingAction);
  822.                 }
  823.             if (mTypingAction != nil)
  824.                 mTypingAction->InputCharacter(theKey);
  825.             else
  826.                 ::TEKey(theKey, mBulletTextEditH);
  827.             UserChangedText();
  828.             break;
  829.  
  830.  
  831.         case keyStatus_TEDelete: {
  832.             if ((**mBulletTextEditH).selEnd > 0)
  833.                 {
  834.                 // Do it to the hidden text edit field
  835.                 ::TEKey(char_Backspace, mTextEditH);
  836.  
  837.                 // Do it to the visible text edit field
  838.                 if (mTypingAction == nil)
  839.                     {
  840.                     mTypingAction = new LTETypingAction(mBulletTextEditH, this, this);
  841.                     PostAction(mTypingAction);
  842.                     }
  843.                 if (mTypingAction != nil)
  844.                     mTypingAction->BackwardErase();
  845.                 else
  846.                     ::TEKey(char_Backspace, mBulletTextEditH);
  847.                 UserChangedText();
  848.                 }
  849.             break; }
  850.  
  851.  
  852.         case keyStatus_TECursor: {
  853.             StFocusAndClipIfHidden    teCursorFocus(this);
  854.             ::TEKey(theKey, mTextEditH);
  855.             ::TEKey(theKey, mBulletTextEditH);
  856.             break; }
  857.  
  858.  
  859.         case keyStatus_ExtraEdit: {
  860.             StFocusAndClipIfHidden    extraEditFocus(this);
  861.             switch (theKey) {            
  862.                 case char_Home:
  863.                     ::TESetSelect(0, 0, mTextEditH);
  864.                     ::TESetSelect(0, 0, mBulletTextEditH);
  865.                     break;
  866.                     
  867.                     
  868.                 case char_End:
  869.                     ::TESetSelect(max_Int16, max_Int16, mTextEditH);
  870.                     ::TESetSelect(max_Int16, max_Int16, mBulletTextEditH);
  871.                     break;
  872.                     
  873.                     
  874.                 case char_FwdDelete:
  875.                     if ((**mBulletTextEditH).selStart < (**mBulletTextEditH).teLength)
  876.                         {
  877.                         // Do it to the hidden record
  878.                         if ((**mTextEditH).selStart == (**mTextEditH).selEnd)
  879.                             ::TESetSelect((**mTextEditH).selStart,
  880.                                             (**mTextEditH).selStart + 1,
  881.                                             mTextEditH);
  882.                         ::TEDelete(mTextEditH);
  883.                         
  884.                         
  885.                         // Do it to the visible record
  886.                         if (mTypingAction == nil)
  887.                             {
  888.                             mTypingAction = new LTETypingAction(mBulletTextEditH, this, this);
  889.                             PostAction(mTypingAction);
  890.                             }
  891.                         if (mTypingAction != nil)
  892.                             mTypingAction->ForwardErase();
  893.                         else
  894.                             if ((**mBulletTextEditH).selStart == (**mBulletTextEditH).selEnd)
  895.                                 ::TESetSelect((**mBulletTextEditH).selStart,
  896.                                                 (**mBulletTextEditH).selStart + 1,
  897.                                                 mTextEditH);
  898.                             ::TEDelete(mTextEditH);
  899.                         UserChangedText();
  900.                         }
  901.                     break;
  902.                     
  903.                     
  904.                 default:
  905.                     keyHandled = LEditField::HandleKeyPress(inKeyEvent);
  906.                     break;
  907.                 }
  908.             break; }
  909.         
  910.  
  911.         case keyStatus_Reject:
  912.             // Can do something with rejected keystrokes here
  913.             SysBeep(30);
  914.             break;
  915.  
  916.  
  917.         case keyStatus_PassUp:
  918.             keyHandled = LEditField::HandleKeyPress(inKeyEvent);
  919.             break;
  920.         }
  921.  
  922.  
  923.  
  924.     // Return as the keystroke was handled or not
  925.     return(keyHandled);
  926. }
  927.  
  928.  
  929.  
  930.  
  931.  
  932.  
  933.  
  934.  
  935.  
  936.  
  937.  
  938.  
  939.  
  940.  
  941.  
  942. //=============================================================================
  943. //        LPasswordField::SelectAll
  944. //-----------------------------------------------------------------------------
  945. //        Select the entire contents of a PasswordField.
  946. //-----------------------------------------------------------------------------
  947. void LPasswordField::SelectAll()
  948. {
  949.  
  950.     // Call our parent class
  951.     LEditField::SelectAll();
  952.     
  953.     
  954.     // Select the visible TextEdit record
  955.     StFocusAndClipIfHidden    focus(this);
  956.     ::TESetSelect(0, max_Int16, mBulletTextEditH);
  957. }
  958.  
  959.  
  960.  
  961.  
  962.  
  963.  
  964.  
  965.  
  966.  
  967.  
  968.  
  969.  
  970.  
  971.  
  972.  
  973. //=============================================================================
  974. //        LPasswordField::AlignTextEditRects
  975. //-----------------------------------------------------------------------------
  976. //        Align the view and destination rectangles of the Toolbox TextEdit
  977. //        records with the Frame of a PasswordField.
  978. //-----------------------------------------------------------------------------
  979. void LPasswordField::AlignTextEditRects()
  980. {    Rect    textFrame;
  981.  
  982.  
  983.  
  984.     // If the Frame is outside QuickDraw space, we put textFrame at
  985.     // the upper left limit of QuickDraw space (extreme negative
  986.     // coordinates). That location is gauranteed to be offscreen
  987.     // (unless you have a control longer than 32K pixels). since
  988.     // PowerPlant Image coordinates start at (0, 0) and are never
  989.     // negative.
  990.     if (!CalcLocalFrameRect(textFrame))
  991.         {
  992.         textFrame.left        = min_Int16;
  993.         textFrame.right        = textFrame.left + mFrameSize.width;
  994.         textFrame.top        = min_Int16;
  995.         textFrame.bottom    = textFrame.top + mFrameSize.height;
  996.         }
  997.  
  998.  
  999.     // If we have a box, move in past it    
  1000.     if (mHasBox)
  1001.         ::InsetRect(&textFrame, 2, 2);
  1002.  
  1003.  
  1004.     // Set the TextEdit view and destination rectangles to be the
  1005.     // same as the Frame. We do *not* set the viewRect of the
  1006.     // mTextEditH TextEdit record, since that's what's keeping it
  1007.     // off screen and out of the way.
  1008. //    (**mTextEditH).viewRect            = textFrame;
  1009.     (**mTextEditH).destRect            = textFrame;
  1010.     (**mBulletTextEditH).viewRect    = textFrame;
  1011.     (**mBulletTextEditH).destRect    = textFrame;
  1012.     AdjustTextWidth(false);
  1013.  
  1014.  
  1015.     // Let TextEdit adjust the line breaks
  1016.     ::TECalText(mTextEditH);
  1017.     ::TECalText(mBulletTextEditH);
  1018. }
  1019.  
  1020.  
  1021.  
  1022.  
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034. //=============================================================================
  1035. //        LPasswordField::AdjustTextWidth
  1036. //-----------------------------------------------------------------------------
  1037. //        Adjust the width of the destination rectangle of the Toolbox TextEdit
  1038. //        record
  1039. //
  1040. //        This function does nothing if WordWrap is ON. If WordWrap is OFF, this
  1041. //        function sets the width of the TextEdit destination rectangle to either
  1042. //        the width of the text or a very large number, depending on the value
  1043. //        of inShrinkToText.
  1044. //
  1045. //        This adjustment is needed to make autoscrolling work properly when
  1046. //        WordWrap is off. While entering text, the destination rectangle should
  1047. //        be very wide so that the text doesn't word wrap. However, while
  1048. //        clicking, it should be just as wide as the text so that the PassField
  1049. //        does not autoscroll past the edge of the text.
  1050. //-----------------------------------------------------------------------------
  1051. void LPasswordField::AdjustTextWidth(Boolean inShrinkToText)
  1052. {    Rect    textFrame;
  1053.     Int16    destWidth = 4000;        // Very Large Number
  1054.     Int16    just;
  1055.     
  1056.  
  1057.  
  1058.     // We adjust only of WordWrap is OFF
  1059.     if (!mHasWordWrap)
  1060.         {
  1061.         // Get the size of the editable text area, taking into account a box
  1062.         CalcLocalFrameRect(textFrame);
  1063.         if (mHasBox)
  1064.             ::InsetRect(&textFrame, 2, 2);
  1065.         
  1066.         
  1067.         
  1068.         // Calculate the width of the text in the PasswordField
  1069.         if (inShrinkToText)
  1070.             {
  1071.             Point    startPoint    = ::TEGetPoint(0, mBulletTextEditH);
  1072.             Point    endPoint    = ::TEGetPoint((**mBulletTextEditH).teLength, mBulletTextEditH);
  1073.             destWidth = endPoint.h - startPoint.h;
  1074.             
  1075.             if (destWidth < textFrame.right - textFrame.left)
  1076.                 destWidth = textFrame.right - textFrame.left;
  1077.             }
  1078.         
  1079.         // Direction to extend dest rect depends on the text justification
  1080.         just = (**mBulletTextEditH).just;
  1081.         if (just == teFlushDefault)
  1082.             {
  1083.             // For left justificaton, GetSysDirection returns teFlushDefault.
  1084.             // For right, it returns teFlushRight
  1085.             just = ::GetSysDirection();
  1086.             }
  1087.  
  1088.  
  1089.         // Case out on the justification        
  1090.         switch ((**mBulletTextEditH).just) {
  1091.             case teFlushLeft:
  1092.             case teFlushDefault:
  1093.                 // Text fixed on left and grows right
  1094.                 (**mBulletTextEditH).destRect.right = (**mBulletTextEditH).destRect.left + destWidth;
  1095.                 break;
  1096.  
  1097.  
  1098.             case teFlushRight:
  1099.                 // Text grows to the left
  1100.                 (**mBulletTextEditH).destRect.left = (**mBulletTextEditH).destRect.right - destWidth;
  1101.                 break;
  1102.  
  1103.  
  1104.             case teCenter:
  1105.                 // Text grows left and right
  1106.                 Int16    center = (textFrame.left + textFrame.right) / 2;
  1107.                 (**mBulletTextEditH).destRect.left = center - 2000;
  1108.                 (**mBulletTextEditH).destRect.right = center + 2000;
  1109.                 break;
  1110.             }
  1111.         }
  1112. }
  1113.  
  1114.  
  1115.  
  1116.  
  1117.  
  1118.  
  1119.  
  1120.  
  1121.  
  1122.  
  1123.  
  1124.  
  1125.  
  1126.  
  1127.  
  1128. //=============================================================================
  1129. //        LPasswordField::BeTarget
  1130. //-----------------------------------------------------------------------------
  1131. //        A PasswordField is becoming the target.
  1132. //-----------------------------------------------------------------------------
  1133. void LPasswordField::BeTarget()
  1134. {
  1135.     // Call our parent class
  1136.     LEditField::BeTarget();
  1137.  
  1138.  
  1139.     // Show the active selection
  1140.     ::TEActivate(mBulletTextEditH);
  1141. }
  1142.  
  1143.  
  1144.  
  1145.  
  1146.  
  1147.  
  1148.  
  1149.  
  1150.  
  1151.  
  1152.  
  1153.  
  1154.  
  1155.  
  1156.  
  1157. //=============================================================================
  1158. //        LPasswordField::DontBeTarget
  1159. //-----------------------------------------------------------------------------
  1160. //        PasswordField is no longet the target.
  1161. //
  1162. //        Our parent removes the PasswordField from the IdleQueue.
  1163. //-----------------------------------------------------------------------------
  1164. void LPasswordField::DontBeTarget()
  1165. {
  1166.  
  1167.     // Call our parent class
  1168.     LEditField::DontBeTarget();
  1169.  
  1170.  
  1171.     // Show the inactive selection
  1172.     ::TEDeactivate(mBulletTextEditH);
  1173. }
  1174.  
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186.  
  1187.  
  1188.  
  1189. //=============================================================================
  1190. //        LPasswordField::SpendTime
  1191. //-----------------------------------------------------------------------------
  1192. //        At idle time, we flash the insertion cursor if necessary.
  1193. //-----------------------------------------------------------------------------
  1194. void LPasswordField::SpendTime(const EventRecord &inMacEvent)
  1195. {
  1196.  
  1197.     // Flash the cursor
  1198.     if (FocusExposed())
  1199.         ::TEIdle(mBulletTextEditH);
  1200. }
  1201.  
  1202.  
  1203.  
  1204.  
  1205.  
  1206.  
  1207.  
  1208.  
  1209.  
  1210.  
  1211.  
  1212.  
  1213.  
  1214.  
  1215.  
  1216. //=============================================================================
  1217. //        LPasswordField::SavePlace
  1218. //-----------------------------------------------------------------------------
  1219. //        Save the TextEdit rectangles.
  1220. //-----------------------------------------------------------------------------
  1221. void LPasswordField::SavePlace(LStream *outPlace)
  1222. {
  1223.     LPane::SavePlace(outPlace);
  1224.     
  1225.     Rect    viewRect = (**mBulletTextEditH).viewRect;
  1226.     outPlace->WriteData(&viewRect, sizeof(Rect));
  1227.  
  1228.     Rect    destRect = (**mBulletTextEditH).destRect;
  1229.     outPlace->WriteData(&destRect, sizeof(Rect));
  1230. }
  1231.  
  1232.  
  1233.  
  1234.  
  1235.  
  1236.  
  1237.  
  1238.  
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246. //=============================================================================
  1247. //        LPasswordField::RestorePlace
  1248. //-----------------------------------------------------------------------------
  1249. //        Restore the TextEdit rectangles.
  1250. //-----------------------------------------------------------------------------
  1251. void LPasswordField::RestorePlace(LStream *inPlace)
  1252. {
  1253.     LPane::RestorePlace(inPlace);
  1254.  
  1255.     Rect    viewRect;
  1256.     inPlace->ReadData(&viewRect, sizeof(Rect));
  1257.     (**mBulletTextEditH).viewRect = viewRect;
  1258.  
  1259.     Rect    destRect;
  1260.     inPlace->ReadData(&destRect, sizeof(Rect));
  1261.     (**mBulletTextEditH).destRect = destRect;
  1262. }
  1263.  
  1264.  
  1265.  
  1266.  
  1267.  
  1268.  
  1269.  
  1270.  
  1271.  
  1272.  
  1273.  
  1274.  
  1275.  
  1276.  
  1277.  
  1278. //=============================================================================
  1279. //        LPasswordField::SetTextToBullets
  1280. //-----------------------------------------------------------------------------
  1281. //        Set every character in a TextEdit record to be the bullet character.
  1282. //-----------------------------------------------------------------------------
  1283. void LPasswordField::SetTextToBullets(TEHandle theTextHnd)
  1284. {    char            *theChar;
  1285.     short            i, theLen;
  1286.  
  1287.  
  1288.     // Get the text, and it's length
  1289.     theChar    = *(::TEGetText(theTextHnd));
  1290.     theLen    = (*theTextHnd)->teLength;
  1291.     
  1292.     
  1293.     // If there's no text, we're done
  1294.     if (theLen == 0)
  1295.         return;
  1296.  
  1297.  
  1298.     // Set every character to the bullet character
  1299.     for (i = 0; i < theLen; i++)
  1300.         *theChar++ = mBullet;
  1301. }
  1302.  
  1303.  
  1304.  
  1305.  
  1306.  
  1307.  
  1308.  
  1309.  
  1310.  
  1311.  
  1312.  
  1313.  
  1314.  
  1315.  
  1316.  
  1317. //=============================================================================
  1318. //        LPasswordField::SetVisibleFromHidden
  1319. //-----------------------------------------------------------------------------
  1320. //        Set every character in mBulletTextEditH to be a bullet character,
  1321. //        adjusting it's length to match mTextEditH if needs be.
  1322. //
  1323. //        mBulletTextEditH is *not* redrawn - call Refresh() after calling this
  1324. //        routine.
  1325. //-----------------------------------------------------------------------------
  1326. void LPasswordField::SetVisibleFromHidden(void)
  1327. {    CharsHandle        theHnd;
  1328.     char            *theChar;
  1329.     short            i, theLen;
  1330.  
  1331.  
  1332.  
  1333.     // Find out how much text is in the off screen TextEdit record
  1334.     theHnd = ::TEGetText(mTextEditH);
  1335.     ::HLock(theHnd);
  1336.     theChar    = *theHnd;
  1337.     theLen    = (*mTextEditH)->teLength;
  1338.     
  1339.     
  1340.     // Set the text of the on screen TextEdit record to match the offscreen
  1341.     ::TESetText(theChar, theLen, mBulletTextEditH);
  1342.     
  1343.     
  1344.     // Unclock the text handle of the off screen TextEdit record
  1345.     ::HUnlock(theHnd);
  1346.  
  1347.     
  1348.     // Convert the text of the on screen record to bullets
  1349.     SetTextToBullets(mBulletTextEditH);
  1350. }
  1351.